#pragma once

#include "stdafx.h"

#ifndef _HAVOK_UTILITIES_
#define _HAVOK_UTILITIES_

// Math and base include
#include <Common/Base/hkBase.h>
#include <Common/Base/System/hkBaseSystem.h>
#include <Common/Base/System/Error/hkDefaultError.h>
#include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>
#include <Common/Base/Monitor/hkMonitorStream.h>
#include <Common/Base/Memory/System/hkMemorySystem.h>
#include <Common/Base/Memory/Allocator/Malloc/hkMallocAllocator.h>

#include <Physics/Collide/hkpCollide.h>	
#include <Physics/Collide/Agent/ConvexAgent/SphereBox/hkpSphereBoxAgent.h>	
#include <Physics/Collide/Shape/Convex/Box/hkpBoxShape.h>					
#include <Physics/Collide/Shape/Convex/Sphere/hkpSphereShape.h>				
#include <Physics/Collide/Dispatch/hkpAgentRegisterUtil.h>					

#include <Physics/Collide/Query/CastUtil/hkpWorldRayCastInput.h>			
#include <Physics/Collide/Query/CastUtil/hkpWorldRayCastOutput.h>			

#include <Physics/Dynamics/World/hkpWorld.h>								
#include <Physics/Dynamics/Entity/hkpRigidBody.h>							
#include <Physics/Utilities/Dynamics/Inertia/hkpInertiaTensorComputer.h>	

#include <Common/Base/Thread/Job/ThreadPool/Cpu/hkCpuJobThreadPool.h>
#include <Common/Base/Thread/Job/ThreadPool/Spu/hkSpuJobThreadPool.h>
#include <Common/Base/Thread/JobQueue/hkJobQueue.h>

#include <Common/Visualize/hkVisualDebugger.h>
#include <Physics/Utilities/VisualDebugger/hkpPhysicsContext.h>				

#include <stdio.h>

static void HK_CALL errorReport( const char* msg, void* userArgGivenToInit ) {
	printf("%s", msg);
}

/** @class PhysicsSystem
 *
 *  @brief Singleton wrapper class that initializes the Havok Physics simulation
 *
 *	@author Simulation engines 2012 group 3
 *
 *  Singleton wrapper that initializes the Havok Physics system, Havok's Visual Debugger service. Create sphere- and box-shapes.
 */
class PhysicsSystem {
public:
	/**
	 *	@brief				Get the singleton instance
	 */
	static PhysicsSystem* getInstance();

	/**
	 *	@brief				Sets up the visual debugger
	 */
	void registerVisualDebugger();

	/**
	 *	@brief				Simulates one step of the simulation. Analogy to the update-method.
	 *
	 *	@param deltaTime	Time in seconds since last update.
	 */
	void stepSimulation(float deltaTime);

	/**
	 *	@brief				Simulates one step of the simulation in the visual debugger.
	 *
	 *	@param deltaTime	Time in seconds since last update.
	 */
	void stepVisualDebugger(float deltaTime);

	/**
	 *	@brief				Creates a physics plane.
	 *
	 *	@param x			Starting point x-axis.
	 *
	 *	@param y			Starting point y-axis.
	 *
	 *	@param z			Starting point z-axis.
	 *
	 *	@param width		Width of plane.
	 *
	 *	@param height		Height of plane.
	 *
	 *	@param thickness	Thickness of plane.
	 */
	void createPlane( float x, float y, float z, float width, float height, float thickness );

	/**
	 *	@brief				Gets the physics world.
	 */
	hkpWorld* getWorld();

	/**
	 *	@brief				Gets the visual debugger.
	 */
	hkVisualDebugger* getVisualDebugger();

private:
	/**
	 *	@brief				Singleton constructor.
	 *
	 *	@param visualDebuggerActive	If the visual debugger is running.
	 */
	PhysicsSystem( bool visualDebuggerActive );

	/**
	 *	@brief				Singleton destructor.
	 */
	virtual ~PhysicsSystem( void );

	static PhysicsSystem* instance;

	/**
	 *	@brief				Initializes the Havok Physics.
	 */
	void initHavok();

	/**
	 *	@brief				Deinitializes the Havok Physics. Cleans up after run.
	 */
	void deinitHavok();

	/**
	 *	@brief				Gravitational force that is working towards centre of planetoid.
	 */
	float gravityForce;

	// Variables for memory needs of HAVOK
	hkMemoryRouter* m_pMemoryRouter;
	hkHardwareInfo m_hardwareInfo;
	int m_iTotalNumThreadsUsed;
	hkCpuJobThreadPoolCinfo m_threadPoolCinfo;
	hkJobThreadPool* m_pThreadPool;
	hkJobQueueCinfo m_jobQueuInfo;
	hkJobQueue* m_pJobQueue;

	// World control variables
	hkpWorldCinfo m_worldInfo;
	hkpWorld* m_pPhysicsWorld;

	// Visual debugger
	bool m_bVisualDebuggerActive;
	hkArray<hkProcessContext*> m_arrayPhysicsContext;
	hkVisualDebugger* m_pVisualDebugger;
	hkpPhysicsContext* m_pPhysicsContext;

public :
	/**
	 *	@brief				Updates the Physics simulation as well as the visual debugger.
	 *
	 *	@param deltaTime	Time in seconds since last update.
	 */
	bool update( float deltaTime );

	/**
	 *	@brief				Adds a fixed (not moving) surface to the physics simulation. It is a thin box.
	 *
	 *	@param position		Position of the surface.
	 *
	 *	@param dimensions	Dimensions of the surface.
	 */
	void addFixedSurface( const hkVector4& position, const hkVector4& dimensions );

	/**
	 *	@brief				Adds a moving box to the physics simulation.
	 *
	 *	@param position		Position of the box.
	 *
	 *	@param dimensions	Dimensions of the box.
	 */
	void addMovingBoxes( const hkVector4& position, const hkVector4& dimensions );

	/**
	 *	@brief				Transforms between a Havok quaternion to a Ogre3d quaternion.
	 *
	 *	@param quat			Quaternion to transform.
	 */
	static Ogre::Quaternion hkQuatToOgre( hkQuaternion& quat );
};

#endif